package com.hb.vest;

import brut.androlib.Androlib;
import brut.androlib.AndrolibException;
import brut.androlib.ApkDecoder;
import brut.androlib.err.CantFindFrameworkResException;
import brut.androlib.err.InFileNotFoundException;
import brut.androlib.err.OutDirExistsException;
import brut.androlib.options.BuildOptions;
import brut.common.BrutException;
import brut.directory.DirectoryException;
import com.android.apksigner.ApkSignerTool;
import org.apache.commons.cli.Options;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

public class Main {
    private static boolean advanceMode = false;
    private static final Options normalOptions = new Options();
    private static final Options decodeOptions = new Options();
    private static final Options buildOptions = new Options();
    private static final Options frameOptions = new Options();
    private static final Options allOptions = new Options();
    private static final Options emptyOptions = new Options();
    private static final Options emptyFrameworkOptions = new Options();
    private static final Options listFrameworkOptions = new Options();

    public Main() {
    }

    public static void main(String[] args) throws BrutException {


        // apktool d [apk]

        // apktool b [apk代码]

        // TODO: 2022/9/20 修改为 通过 commandLine 获取apk路径 方便Jenkins命令执行
        String apkPath = "/Users/hukai/IdeaProjects/hbVest/apk/app-dev-release-79999(1).apk";

        System.out.println("CurrentPath:" + apkPath);
        File apkFile = new File(apkPath);

        //  /Users/hukai/IdeaProjects/hbVest/apk/app-dev-release-79999 (1).apk
        System.out.println("apkFile:" + apkFile.getName());

        //解压 apk
        File outputDir = decodeApk(apkFile);

        // 替换key
        // 文件不存在，结束程序
        if (!outputDir.exists()) {
            System.out.println("outputDir not found");
            System.exit(0);
        }
        // TODO: 2022/9/20 包名.xml  包名也从命令行传入、支持多包名(循环构建多个马甲包)
        // TODO: 2022/9/21 还需要拿到 旧包名？ 或者从 manifest 中获取
        String newPackageName = "com.jiaoliuqu.fengyue";
        String resourcePath = Main.class.getClassLoader().getResource(newPackageName+".xml").getPath();
        File resourceFile = new File(resourcePath);
        XmlReplaceTools.initKey(resourceFile);

        XmlReplaceTools.replaceManifest(outputDir);
        XmlReplaceTools.replacePackageName("com.jiaoliuqu.tuodan", newPackageName, outputDir);
        XmlReplaceTools.replaceStringXml(outputDir);


        // 重打包
        // apktool b [decodeDir]
        buildApk(outputDir);

        // 重签
        // V1\V2 混签
        //java -jar apksigner.jar sign --ks [签名文件] --ks-key-alias [别名] --ks-pass pass:[密码] --key-pass pass:[密码] --out [sign apk] [unSign apk]
        try {
            List<String> cli = new ArrayList<String>();
            cli.add("sign");
            cli.add("--ks");
            cli.add(Main.class.getClassLoader().getResource("xingjiabi_sign").getPath());
            cli.add("--ks-key-alias");
            cli.add("xingjiabi");
            cli.add("--ks-pass");
            cli.add("pass:haibao2309");
            cli.add("--key-pass");
            cli.add("pass:haibao2309");
            cli.add("--out");
            // 已签名apk
            cli.add(outputDir.getPath()+"/dist/"+newPackageName+"_sign.apk");
            // 未签名文件
            cli.add(outputDir.getPath()+"/dist/"+apkFile.getName());

            ApkSignerTool.main(cli.toArray(String[]::new));
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.exit(0);

    }

    /**
     * 打包 apk
     *
     * @param outputDir
     */
    private static void buildApk(File outputDir) {
        BuildOptions buildOptions = new BuildOptions();
        try {
            buildOptions.useAapt2 = true;
            buildOptions.forceBuildAll = true;
            buildOptions.forceDeleteFramework = true;
            Androlib androlib = (new Androlib(buildOptions));
            androlib.emptyFrameworkDirectory();
//            androlib.ma
            androlib.build(outputDir, null);
        } catch (BrutException e) {
            e.printStackTrace();
        }
    }

    /**
     * 解压Apk
     * 原命令 apktool d [apk路径]
     * 解压到当前jar包路径下
     *
     * @return decodeDir 解包路径
     */
    private static File decodeApk(File apk) {
        Androlib androlib = new Androlib();
//        androlib.
        ApkDecoder decoder = new ApkDecoder(androlib);
        String apkName = apk.getName();

        System.out.println("apkName:" + apk.getName());

        File outDir;
        String outName = apkName.endsWith(".apk") ? apkName.substring(0, apkName.length() - 4).trim() : apkName + ".out";
        outName = (new File(outName)).getName();
        outDir = new File(outName);
        decoder.setOutDir(outDir);
        decoder.setApkFile(apk);

        try {
            decoder.setForceDelete(true);
            decoder.setForceDecodeManifest((short) 1);
            decoder.setDecodeResources((short) 257);
            decoder.decode();
        } catch (OutDirExistsException var22) {
            System.err.println("Destination directory (" + outDir.getAbsolutePath() + ") already exists. Use -f switch if you want to overwrite it.");
            System.exit(1);
        } catch (InFileNotFoundException var23) {
            System.err.println("Input file (" + apkName + ") was not found or was not readable.");
            System.exit(1);
        } catch (CantFindFrameworkResException var24) {
            System.err.println("Can't find framework resources for package of id: " + var24.getPkgId() + ". You must install proper framework files, see project website for more info.");
            System.exit(1);
        } catch (IOException var25) {
            System.err.println("Could not modify file. Please ensure you have permission.");
            System.exit(1);
        } catch (DirectoryException var26) {
            System.err.println("Could not modify internal dex files. Please ensure you have permission.");
            System.exit(1);
        } catch (AndrolibException e) {
            e.printStackTrace();
        } finally {
            try {
                decoder.close();
            } catch (IOException var21) {
            }

        }
        return outDir;
    }
}
